為了API的安全性,本次跟各位介紹透過JWT Token來幫API做身分驗證,簡單來說就是先讓使用者登入來取得Token,接下來需使用得到的Token進行其他API的訪問,並可以在程式當中透過Token來判別目前的使用者是誰.
$ sail composer require tymon/jwt-auth 1.*@rc
$ sail artisan vendor:publish --provider="Tymon\JWTAuth\Providers\LaravelServiceProvider"
$ sail artisan jwt:secret
<?php
namespace App\Models;
use Tymon\JWTAuth\Contracts\JWTSubject;
use Illuminate\Foundation\Auth\User as Authenticatable;
use App\Models\Post;
class User extends Authenticatable implements JWTSubject
{
    /**
     * Get the identifier that will be stored in the subject claim of the JWT.
     *
     * @return mixed
     */
    public function getJWTIdentifier()
    {
        return $this->getKey();
    }
    /**
     * Return a key value array, containing any custom claims to be added to the JWT.
     *
     * @return array
     */
    public function getJWTCustomClaims()
    {
        return [];
    }
}
config/app.php內註冊兩個Facade,為了是方便使用JWTAuth和JWTFactory的功能'aliases' => [
    ...
    'JWTAuth' => 'Tymon\JWTAuth\Facades\JWTAuth',
    'JWTFactory' => 'Tymon\JWTAuth\Facades\JWTFactory',
],
config/auth.php
'defaults' => [
    'guard' => 'api',
    'passwords' => 'users',
],
...
'guards' => [
    'web' => [
        'driver' => 'session',
        'provider' => 'users',
    ],
    'api' => [
        'driver' => 'jwt',
        'provider' => 'users',
    ],
],
routes/api.php
<?php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\AuthController;
Route::group(['prefix' => 'auth'], function () {
    Route::post('login', [AuthController::class, 'login']);
    Route::post('register', [AuthController::class, 'register']);
});
$ sail artisan make:controller AuthController
$ sail artisan make:service AuthService
$ sail artisan make:repository UserRepository
<?php
namespace App\Http\Controllers;
use App\Services\AuthService;
use Illuminate\Http\Request;
use Tymon\JWTAuth\Facades\JWTAuth;
class AuthController extends Controller
{
    protected $service;
    public function __construct(AuthService $service)
    {
        $this->middleware('jwt.auth', ['except' => ['login', 'register']]);
        $this->service = $service;
    }
    /**
     * 登入取得Token
     * @param Request $request
     * @return JsonResponse
     */
    public function login(Request $request)
    {
        $account = $request->input('account');
        $password = $request->input('password');
        $token = $this->service->login($account, $password);
        if ($token !== false) {
            $result = [
                'token_type' => 'Bearer',
                'access_token' => $token,
                'expires_in' => auth('api')->factory()->getTTL() * 60
            ];
        }
        return response()->json($result);
    }
    
    /**
     * 註冊使用者
     * @param Request $request
     * @return JsonResponse
     */
    public function register(Request $request)
    {
        $result = $this->service->register($request->all());
        return response()->json($result);
    }
}
JWTAuth::fromUser($user)方法建立token,但token的建立不只一種,本範例這是基於User model返回instance產生token,好處是之後可以透過$user = Auth::guard('api')->user()取得User model進行使用<?php
namespace App\Services;
use App\Repositories\UserRepository;
use Tymon\JWTAuth\Facades\JWTAuth;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Hash;
class AuthService
{
    /**
     * @var UserRepository
     */
    protected $user_repository;
    public function __construct(UserRepository $user_repository)
    {
        $this->user_repository = $user_repository;
    }
    public function login(string $account, string $password)
    {
        $user = $this->user_repository->searchUserByAccount($account);
        // 密碼不符
        if (! Hash::check($password, $user->password)) {
            // TODO error handler
            dd('password not matched');
        }
        return JWTAuth::fromUser($user);
    }
    public function register(array $data)
    {
        $name = Arr::get($data, 'name');
        $account = Arr::get($data, 'account');
        $password = Arr::get($data, 'password');
        $user = $this->user_repository->registerAccount($name, $account, $password);
        return $user;
    }
}
<?php
namespace App\Repositories;
use Exception;
use App\Models\User;
use Illuminate\Support\Facades\Hash;
class UserRepository
{
    /**
     * 透過帳號搜尋特定使用者
     *
     * @param string $account 帳號
     * @return mixed
     */
    public function searchUserByAccount(string $account)
    {
        try {
            return User::select(['*'])
                ->where('account', $account)
                ->first();
        } catch (Exception $e) {
            dd($e);
        }
    }
    /**
     * 建立使用者
     *
     * @param string $name 姓名
     * @param string $account 帳號
     * @param string $password 密碼
     * @return mixed
     */
    public function registerAccount(string $name, string $account, string $password)
    {
        try {
            return User::create([
                'name' => $name,
                'account' => $account,
                'password' => Hash::make($password),
            ]);
        } catch (Exception $e) {
            dd($e);
        }
    }
}
設定完成後,如果之後建立的API希望透過token驗證,可以在route處加上Route::middleware(['jwt.auth'])如下
# /routes/api.php
Route::middleware(['jwt.auth'])->group(function () {
    Route::group(['prefix' => 'user'], function () {
        Route::get('/', [UserController::class, 'index']);
    });
    Route::group(['prefix' => 'post'], function () {
        Route::post('/', [PostController::class, 'create']);
        Route::get('/', [PostController::class, 'index']);
    });
});
接下來使用Postman進行測試
先註冊一個新的User
POST /auth/register
登入取得Token
POST /auth/login
當API需要Authentication時,Header處加上Authorization
以上就是這次Authorization的介紹,網路上有很多關於Jwt token的介紹非常的詳細,這次是透過之前使用過的經驗加上網路上爬文分享實務上的經驗給大家,希望對大家有幫助